home *** CD-ROM | disk | FTP | other *** search
- // Copyright 1994 by Jon Dart. All Rights Reserved.
-
- // Stand-alone executable to build the binary opening book from
- // a text file.
-
- // There are two book files, one for moves by White and one for
- // Black. Each book consists of three portions: a header, a hash
- // table, and an array of book entries.
-
- // The header is 8 bytes:
- // offset
- // 0 version number
- // 1-2 hash table size
- // 3-4 number of book entries
- // 5-7 unused
-
- // The hash table is an array of unsigned indexes into the book
- // entry array. A hash code for the position modulo the hash table
- // size is used to look up in this array the first book entry for the
- // position.
-
- // The book entries themselves are structures defined in bookentr.h.
- // Each one is 8 bytes and contains the full hash code, the move
- // index, a weight indicating how often the computer should play the
- // move, and an index to the next entry in the hash chain.
-
- // Each book is limited to 65536 bytes, enough to hold slightly over
- // 8000 moves.
-
- #include "board.h"
- #include "array.h"
- #include "emove.h"
- #include "bookentr.h"
- // #include "bookwrit.h"
- #include "hash.h"
- #include "bhash.h"
- #include "movegen.h"
- #include "notation.h"
- #include "types.h"
- extern "C"
- {
- #include <string.h>
- #include <ctype.h>
- #include <assert.h>
- };
-
- #include <fstream.h>
- #include <iostream.h>
-
- const unsigned MAX_MOVES = 8050;
- const unsigned HASH_TABLE_SIZE = 511;
-
- struct book_info
- {
- unsigned next_free;
- Array < unsigned >*hash_table;
- Array < Book_Entry * >*book_moves;
- };
-
- static book_info book_data[2];
-
- const int Entry_Size = sizeof(Book_Entry);
- const int Header_Size = 8;
- const int Buffer_Size = 4096;
- const byte Book_Version = 2;
-
- static Boolean
- search(const unsigned start, const unsigned move_index,
- const ColorType side,
- const unsigned long hc)
- {
- unsigned indx = start;
- byte hibytes[3];
- Book_Entry be(hc, 0, move_index, 0);
- while (indx != INVALID)
- {
- assert(indx < MAX_MOVES);
- Book_Entry *entry = (*(book_data[side].book_moves))[indx];
- if (*entry == be && entry->move_index == move_index)
- return True;
- indx = entry->next;
- }
- return False;
- }
-
- static void
- add_move(const Board & board, int move_index, int recommend)
- {
- unsigned probe = (unsigned) (Board_Hash::HashCode2(board) % HASH_TABLE_SIZE);
- unsigned hit = (*(book_data[board.Side()].hash_table))[probe];
- if (hit == INVALID || !search(hit, move_index, board.Side(),
- board.HashCode()))
- {
- Book_Entry *new_entry = new Book_Entry(board.HashCode(), recommend,
- move_index, hit);
- assert(new_entry);
- unsigned next = book_data[board.Side()].next_free;
- (*(book_data[board.Side()].book_moves))[next] = new_entry;
- (*(book_data[board.Side()].hash_table))[probe] = next;
- #ifdef DEBUG
- cout << "p:" << probe << " h:" << board.HashCode() << " i:"
- << move_index << " f:" << next << endl;
- #endif
- book_data[board.Side()].next_free++;
- }
- }
-
- static void
- write_book(const ColorType side)
- {
- byte *write_buffer = new byte[Buffer_Size];
- assert(write_buffer);
- static char *Book_File_Name[2] = {"bookb", "bookw"};
- ofstream book_file(Book_File_Name[side],
- #ifdef __BORLANDC__
- ios::out | ios::trunc | ios::binary);
- #else
- ios::out | ios::trunc);
- #endif
- if (!book_file.good())
- return;
-
- // write the header
-
- book_file.put((char)Book_Version);
- unsigned ht_size = HASH_TABLE_SIZE;
- book_file.write((char *) &ht_size, (int) sizeof(unsigned));
- book_file.write((char *) (&(book_data[side].next_free)),
- (int) sizeof(unsigned));
- // pad out the header to 8 bytes:
- char stuff[3] = {'\0', '\0', '\0'};
- book_file.write(stuff, 3);
-
- // write the hash table
-
- for (int i = 0; i < HASH_TABLE_SIZE; i++)
- {
- unsigned ht_entry = (*(book_data[side].hash_table))[i];
- book_file.put((char)(ht_entry % 256));
- book_file.put((char)(ht_entry / 256));
- }
-
- // write the book moves
-
- unsigned index = 0;
- unsigned limit = book_data[side].next_free;
- for (i = 0; i < limit; i++)
- {
- if (index + sizeof(Book_Entry) <= Buffer_Size)
- {
- memcpy(write_buffer + index,
- (*(book_data[side].book_moves))[i], sizeof(Book_Entry));
- index += sizeof(Book_Entry);
- } else
- {
- unsigned to_go = Buffer_Size - index;
- memcpy(write_buffer + index,
- (*(book_data[side].book_moves))[i], to_go);
- book_file.write(write_buffer, Buffer_Size);
- memcpy(write_buffer,
- (*(book_data[side].book_moves))[i] + to_go, sizeof(Book_Entry) - to_go);
- index = sizeof(Book_Entry) - to_go;
- }
- }
- if (index)
- book_file.write(write_buffer, index);
- book_file.close();
- delete[] write_buffer;
-
- cout << book_data[side].next_free << " moves in "
- << side << " book." << endl;
- }
-
- int
- main(int argc, char **argv)
- {
- char book_name[128];
- fstream infile;
-
- if (argc < 2)
- strcpy(book_name, "BOOK.TXT");
- else
- strcpy(book_name, argv[1]);
-
- infile.open(book_name, ios::in);
- if (!infile.good())
- {
- cerr << "Can't open book file: " << book_name << endl;
- return -1;
- }
- book_data[White].book_moves = new Array < Book_Entry * >(MAX_MOVES, False);
- book_data[Black].book_moves = new Array < Book_Entry * >(MAX_MOVES, False);
- book_data[White].hash_table = new Array < unsigned >(HASH_TABLE_SIZE, False);
- book_data[Black].hash_table = new Array < unsigned >(HASH_TABLE_SIZE, False);
- book_data[White].next_free = 0;
- book_data[Black].next_free = 0;
-
- char buf[128];
- char movebuf[20];
- unsigned line = 0;
- char *q;
- Board board;
- Board tmpboard;
- int recommend;
- Move moves[Move_Generator::MaxMoves];
- int dots = 0;
-
- for (unsigned i = 0; i < HASH_TABLE_SIZE; i++)
- {
- (*(book_data[White].hash_table))[i] = INVALID;
- (*(book_data[Black].hash_table))[i] = INVALID;
- }
-
- for (i = 0; i < MAX_MOVES; i++)
- {
- (*(book_data[White].book_moves))[i] = NULL;
- (*(book_data[Black].book_moves))[i] = NULL;
- }
-
- while (!infile.eof() && book_data[White].next_free < MAX_MOVES
- && book_data[Black].next_free < MAX_MOVES)
- {
- recommend = 5;
- infile.getline(buf, 128);
- #ifdef DEBUG
- cout << buf << endl;
- #endif
- line++;
- char *p = buf;
- while (isspace(*p))
- p++;
- switch (*p)
- {
- case '\0':
- continue;
- case ';':
- continue;
- case 'm':
- tmpboard = board;
- continue;
- case 'r':
- board = tmpboard;
- continue;
- case 's':
- case 't':
- break; // these are obsolete
-
- case '-':
- board.Reset();
- break;
- default:
- {
- while (*p)
- {
- while (isspace(*p))
- p++;
- if (*p == '\0')
- break;
- q = movebuf;
- int count = 0;
- while (!isspace(*p) && *p && count < 19)
- {
- *q++ = *p++;
- ++count;
- }
- *q = '\0';
- Move move = Notation::Value(board, board.Side(), movebuf);
- if (move.IsNull())
- {
- cerr << endl << "Illegal move in file, line " <<
- line << " (" << movebuf << ")" << endl;
- infile.close();
- return -1;
- }
- ExtendedMove emove(board, move);
-
- // check (pseudo) legality:
- Move_Generator mg(board, 0, Move::NullMove());
- int found = 0;
- int move_indx = 0;
-
- int n = mg.Generate_Moves(moves, False, True);
-
- for (int i = 0; i < n; i++)
- {
- if (moves[i] == emove)
- {
- move_indx = i;
- found++;
- break;
- }
- }
- if (!found)
- {
- cerr << endl << "Illegal move in file, line " << line << " ("
- << movebuf << ")" << endl;
- infile.close();
- return -1;
- }
- dots++;
- if (dots % 50 == 0)
- cout << '.';
- if (dots > 3000)
- {
- cout << endl;
- dots = 1;
- }
- while (isspace(*p))
- p++;
- if (*p)
- {
- if ((*p >= '0') && (*p <= '9'))
- {
- recommend = *p - '0';
- p++;
- }
- }
- add_move(board, move_indx, recommend);
- board.MakeMove(emove);
- }
- }
- }
- }
- infile.close();
-
- cout << endl;
- write_book(White);
- write_book(Black);
- return 0;
- }
-